using System.Net.Sockets;
using System.Threading;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;

namespace muduoDotNet
{
    /// <summary>
    /// Poller的抽象基类，用于IO多路复用
    /// </summary>
    public abstract class Poller : IDisposable
    {
        protected readonly EventLoop _loop;
        protected bool _disposed;
        protected readonly Dictionary<int, Channel> _channels;
        protected readonly object _channelsLock;

        protected Poller(EventLoop loop)
        {
            _loop = loop ?? throw new ArgumentNullException(nameof(loop));
            _disposed = false;
            _channels = new Dictionary<int, Channel>();
            _channelsLock = new object();
        }

        public EventLoop Loop => _loop;

        /// <summary>
        /// 轮询IO事件
        /// </summary>
        /// <param name="timeoutMs">超时时间（毫秒）</param>
        /// <returns>活跃的Channel列表</returns>
        public abstract List<Channel> Poll(int timeoutMs);

        /// <summary>
        /// 更新Channel的事件注册
        /// </summary>
        /// <param name="channel">要更新的Channel</param>
        public abstract void UpdateChannel(Channel channel);

        /// <summary>
        /// 移除Channel
        /// </summary>
        /// <param name="channel">要移除的Channel</param>
        public abstract void RemoveChannel(Channel channel);

        /// <summary>
        /// 检查Channel是否在当前Poller中注册
        /// </summary>
        /// <param name="channel">要检查的Channel</param>
        /// <returns>如果已注册则返回true</returns>
        public bool HasChannel(Channel channel)
        {
            _loop.AssertInLoopThread();
            lock (_channelsLock)
            {
                return _channels.ContainsKey(channel.Fd);
            }
        }

        /// <summary>
        /// 创建Poller实例
        /// </summary>
        /// <param name="loop">事件循环</param>
        /// <returns>Poller实例</returns>
        public static Poller NewDefaultPoller(EventLoop loop)
        {
            // 根据平台选择最适合的Poller实现
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                Logger.Info("Using EpollPoller for Linux platform");
                return new EpollPoller(loop);
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                Logger.Info("Using IocpPoller for Windows platform");
                return new IocpPoller(loop);
            }
            else
            {
                // macOS或其他平台使用传统Select实现
                Logger.Info("Using SelectPoller for compatibility");
                return new SelectPoller(loop);
            }
        }

        public void Dispose()
        {
            if (!_disposed)
            {
                _disposed = true;
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                lock (_channelsLock)
                {
                    _channels.Clear();
                }
            }
        }
    }

    /// <summary>
    /// 基于Socket.Select的Poller实现，适用于Windows和跨平台
    /// </summary>
    public class SelectPoller : Poller
    {
        private readonly Dictionary<Socket, Channel> _socketToChannel;
        private readonly object _socketLock;

        public SelectPoller(EventLoop loop)
            : base(loop)
        {
            _socketToChannel = new Dictionary<Socket, Channel>();
            _socketLock = new object();
        }

        public override List<Channel> Poll(int timeoutMs)
        {
            var activeChannels = new List<Channel>();
            
            List<Socket> readSockets = new List<Socket>();
            List<Socket> writeSockets = new List<Socket>();
            List<Socket> errorSockets = new List<Socket>();
            
            // 收集需要检查的Socket
            lock (_socketLock)
            {
                foreach (var pair in _socketToChannel)
                {
                    var socket = pair.Key;
                    var channel = pair.Value;
                    
                    if (channel.Events.HasFlag(EventType.ReadEvent))
                    {
                        readSockets.Add(socket);
                    }
                    if (channel.Events.HasFlag(EventType.WriteEvent))
                    {
                        writeSockets.Add(socket);
                    }
                    // 总是检查错误事件
                    errorSockets.Add(socket);
                }
            }
            
            if (readSockets.Count == 0 && writeSockets.Count == 0 && errorSockets.Count == 0)
            {
                // 没有Socket需要检查，直接等待
                Thread.Sleep(Math.Min(timeoutMs, 10));
                return activeChannels;
            }
            
            try
            {
                // 使用Socket.Select进行多路复用
                int timeoutMicroseconds = timeoutMs * 1000;
                Socket.Select(readSockets, writeSockets, errorSockets, timeoutMicroseconds);
                
                // 处理有事件的Socket
                lock (_socketLock)
                {
                    // 处理读事件
                    foreach (var socket in readSockets)
                    {
                        if (_socketToChannel.TryGetValue(socket, out var channel))
                        {
                            channel.Revents |= EventType.ReadEvent;
                            if (!activeChannels.Contains(channel))
                            {
                                activeChannels.Add(channel);
                            }
                        }
                    }
                    
                    // 处理写事件
                    foreach (var socket in writeSockets)
                    {
                        if (_socketToChannel.TryGetValue(socket, out var channel))
                        {
                            channel.Revents |= EventType.WriteEvent;
                            if (!activeChannels.Contains(channel))
                            {
                                activeChannels.Add(channel);
                            }
                        }
                    }
                    
                    // 处理错误事件
                    foreach (var socket in errorSockets)
                    {
                        if (_socketToChannel.TryGetValue(socket, out var channel))
                        {
                            channel.Revents |= EventType.ErrorEvent;
                            if (!activeChannels.Contains(channel))
                            {
                                activeChannels.Add(channel);
                            }
                        }
                    }
                }
            }
            catch (SocketException ex)
            {
                Logger.Error($"Socket.Select error: {ex.SocketErrorCode}", ex);
                // 发生错误时，标记所有Channel为错误状态
                lock (_socketLock)
                {
                    foreach (var channel in _socketToChannel.Values)
                    {
                        channel.Revents = EventType.ErrorEvent;
                        if (!activeChannels.Contains(channel))
                        {
                            activeChannels.Add(channel);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Fatal("Unexpected error in Poll", ex);
                throw new IoException("Poll operation failed", ex);
            }
            
            return activeChannels;
        }

        public override void UpdateChannel(Channel channel)
        {
            _loop.AssertInLoopThread();
            
            var socket = SocketManager.GetSocket(channel.Fd);
            if (socket == null)
            {
                Logger.Warning($"Cannot find socket for fd {channel.Fd}, removing channel");
                // 如果Socket不存在，直接移除Channel
                lock (_channelsLock)
                {
                    _channels.Remove(channel.Fd);
                }
                channel.SetAddedToPoller(false);
                return;
            }
            
            lock (_socketLock)
            {
                if (channel.Events == EventType.None)
                {
                    // 移除Channel
                    _socketToChannel.Remove(socket);
                    lock (_channelsLock)
                    {
                        _channels.Remove(channel.Fd);
                    }
                    channel.SetAddedToPoller(false);
                }
                else
                {
                    // 添加或更新Channel
                    _socketToChannel[socket] = channel;
                    lock (_channelsLock)
                    {
                        _channels[channel.Fd] = channel;
                    }
                    channel.SetAddedToPoller(true);
                }
            }
        }

        public override void RemoveChannel(Channel channel)
        {
            _loop.AssertInLoopThread();
            
            var socket = SocketManager.GetSocket(channel.Fd);
            if (socket != null)
            {
                lock (_socketLock)
                {
                    _socketToChannel.Remove(socket);
                }
            }
            
            lock (_channelsLock)
            {
                _channels.Remove(channel.Fd);
            }
            
            channel.SetAddedToPoller(false);
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (disposing)
            {
                lock (_socketLock)
                {
                    _socketToChannel.Clear();
                }
            }
        }
    }

    /// <summary>
    /// Socket到Channel的映射管理器
    /// 解决fd到Socket映射的问题
    /// </summary>
    public static class SocketManager
    {
        private static readonly ConcurrentDictionary<int, Socket> _fdToSocket = new ConcurrentDictionary<int, Socket>();
        
        public static void RegisterSocket(Socket socket)
        {
            if (socket != null && !socket.Handle.Equals(IntPtr.Zero))
            {
                _fdToSocket.TryAdd(socket.Handle.ToInt32(), socket);
            }
        }
        
        public static void UnregisterSocket(Socket socket)
        {
            if (socket != null && !socket.Handle.Equals(IntPtr.Zero))
            {
                _fdToSocket.TryRemove(socket.Handle.ToInt32(), out _);
            }
        }
        
        public static Socket GetSocket(int fd)
        {
            _fdToSocket.TryGetValue(fd, out var socket);
            return socket;
        }
    }
}